/*!
 * \file nuExecMgr.cpp
 * \brief Execute object manager.
 * \author Nus
 * \date 2008/02/17, 01:26
 */

#include "nuExecMgr.h"

//! \brief Default constructor.
nuExecMgr::nuExecMgr(u32 num_pri)
    : mNumPriority(num_pri),
      mpNumOfExecObj(NULL),
      mpExecute(NULL),
      mpLast(NULL)
{
  ASSERT_C(mNumPriority > 0);

  // Use system allocator by default.
  mpNumOfExecObj = nuNew u32[mNumPriority];
  ASSERT_C(mpNumOfExecObj != NULL);
  mpExecute = nuNew nuExecute* [mNumPriority];
  ASSERT_C(mpExecute != NULL);
  mpLast = nuNew nuExecute* [mNumPriority];
  ASSERT_C(mpLast != NULL);
  
  for(u32 ui = 0; ui < mNumPriority; ui++) {
    mpNumOfExecObj[ui] = 0;
    mpExecute[ui] = NULL;
    mpLast[ui] = NULL;
  }
}

//! \brief Default destructor.
nuExecMgr::~nuExecMgr()
{
#ifndef _NDEBUG
  // Sanity check...
  for(u32 ui = 0; ui < mNumPriority; ui++)
    ASSERT_C(mpNumOfExecObj[ui] == 0);
#endif
  SAFE_DELETE_ARRAY(mpNumOfExecObj);
  SAFE_DELETE_ARRAY(mpExecute);
  SAFE_DELETE_ARRAY(mpLast);
}

// Add execute object.
s32 nuExecMgr::addExecObj(nuExecute* p_obj, u32 priority)
{
  ASSERT_C(p_obj->mExecutePriority < 0);
  ASSERT_C(priority < mNumPriority);
  
  nuExecute** p_exec = &mpExecute[priority];
  nuExecute** p_last = &mpLast[priority];
  
  if(*p_last) {
    (*p_last)->mpNext = p_obj;
    p_obj->mpPrev = *p_last;
    mpLast[priority] = p_obj;
  } else {
    *p_exec = p_obj;
    *p_last = p_obj;
  }
  p_obj->mExecutePriority = static_cast< s32 >(priority);
  mpNumOfExecObj[priority]++;

  return EC_NONE;
}

// Remove execute object.
s32 nuExecMgr::removeExecObj(nuExecute* p_obj)
{
  ASSERT_C(p_obj->mExecutePriority >= 0);
  ASSERT_C(p_obj->mExecutePriority < mNumPriority);

  s32 priority = p_obj->mExecutePriority;
  nuExecute** p_exec = &mpExecute[priority];
  nuExecute** p_last = &mpLast[priority];
  
  nuExecute* prev = p_obj->mpPrev;
  nuExecute* next = p_obj->mpNext;
  
  if(prev)
    prev->mpNext = next;
  if(next)
    next->mpPrev = prev;

  if(p_obj == *p_exec)
    *p_exec = next;
  if(p_obj == *p_last)
    *p_last = prev;
  
  p_obj->mExecutePriority = -1;
  p_obj->mpNext = NULL;
  p_obj->mpPrev = NULL;

  mpNumOfExecObj[priority]--;

  return EC_NONE;
}
